#include <arpa/inet.h>
#include <cstring>
#include <charconv>

#include "string_operator.h"

namespace eniac
{

std::uint32_t ipv4_to_net_int(const std::string& ipv4)
{
    struct in_addr addr;
    
    if (inet_pton(AF_INET, ipv4.c_str(), &addr) != 1)
    {
        memset(&addr, 0x00, sizeof(in_addr));
    }

    // return ntohl(addr.s_addr);
    return addr.s_addr;
}

std::string host_int_to_ipv4(const uint32_t ipv4)
{
    struct in_addr addr;
    addr.s_addr = htonl(ipv4);

    char buffer[INET_ADDRSTRLEN];
    if (inet_ntop(AF_INET, &addr, buffer, sizeof(buffer)) == nullptr)
    {
        return "";
    }

    return std::string(buffer);
}

std::array<std::uint8_t, 16> ipv6_to_array(const std::string& ipv6)
{
    struct in6_addr addr;
    std::array<std::uint8_t, 16> ret {0};

    if (inet_pton(AF_INET6, ipv6.c_str(), &addr) != 1)
    {
        return ret;
    }

    memcpy(ret.data(), &addr, sizeof(addr));
    return ret;
}

std::string array_to_ipv6(const std::array<std::uint8_t, 16>& ipv6)
{
    char buffer[INET6_ADDRSTRLEN] = "0x0";
    if (inet_ntop(AF_INET6, ipv6.data(), buffer, sizeof(buffer)) == nullptr)
    {
        return "";
    }
    return std::string(buffer);
}

std::string int_to_string(std::int64_t value)
{
    return std::to_string(value);
}

std::vector<std::string> split_string(const std::string& origin_string, const char delimiter)
{
    std::vector<std::string> parts;
    size_t start = 0;
    size_t end = 0;

    while ((end = origin_string.find(delimiter, start)) != std::string::npos)
    {
        parts.push_back(origin_string.substr(start, end - start));
        start = end + 1;
    }

    if (start < origin_string.size())
    {
        parts.push_back(origin_string.substr(start));
    }

    return parts;
}

bool is_valid_ipv4_ip(const std::string& ip)
{
    std::vector<std::string> parts = split_string(ip, '.');

    if (parts.size() != 4)
    {
        return false;
    }
    
    for (const auto& part : parts)
    {
        if (part.empty() || part.size() > 3) {
            return false;
        }
        
        int value;
        auto result = std::from_chars(part.data(), part.data() + part.size(), value);
        
        if (result.ec != std::errc() || result.ptr != part.data() + part.size())
        {
            return false;
        }
        
        if (value < 0 || value > 255)
        {
            return false;
        }
        
        // 检查前导零
        if (part.size() > 1 && part[0] == '0')
        {
            return false;
        }
    }
    
    return true;
}

} /* namespace eniac */